Skip to content

Comments

feat(circleci): add read/workflow insights components#3235

Open
bitdeckai wants to merge 1 commit intosuperplanehq:mainfrom
bitdeckai:bounty-circleci-expand
Open

feat(circleci): add read/workflow insights components#3235
bitdeckai wants to merge 1 commit intosuperplanehq:mainfrom
bitdeckai:bounty-circleci-expand

Conversation

@bitdeckai
Copy link

Summary

Adds five new CircleCI integration components and client methods to support read/insights use cases requested in #3223.

New components

  • circleci.getWorkflow
  • circleci.getLastWorkflow
  • circleci.getRecentWorkflowRuns
  • circleci.getTestMetrics
  • circleci.getFlakyTests

What changed

  • Added corresponding API methods in pkg/integrations/circleci/client.go
  • Registered components in pkg/integrations/circleci/circleci.go
  • Added component implementations under pkg/integrations/circleci/
  • Applied gofmt formatting

Notes

  • Local go test was blocked by transient network timeouts to proxy.golang.org while downloading dependencies.

Closes #3223

@bitdeckai bitdeckai mentioned this pull request Feb 24, 2026
11 tasks
if err != nil {
return err
}
workflow, err := client.GetWorkflow(config.WorkflowID)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow data silently lost due to typed struct

Medium Severity

The GetWorkflow component calls client.GetWorkflow() which unmarshals into WorkflowResponse — a struct with only 5 fields (id, name, status, created_at, stopped_at). The CircleCI API returns additional fields like pipeline_id, pipeline_number, project_slug, started_by, and tag, all silently dropped during deserialization. When Emit() calls json.Marshal() on the output, only those 5 fields are preserved. The same data loss affects GetLastWorkflow via GetPipelineWorkflows(). All the other new read components correctly use map[string]any to preserve complete API responses.

Additional Locations (1)

Fix in Cursor Fix in Web

return map[string]any{
"pipeline": pipelineResp,
"workflows": []any{},
}, nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent pipeline field shape across code paths

Medium Severity

When no pipelines are found, the pipeline field is set to pipelineResp — the full paginated list response (containing items, next_page_token, etc.). When pipelines are found, pipeline is set to firstItem — a single pipeline object (containing id, number, state, etc.). Downstream consumers processing result["pipeline"] will encounter a completely different schema depending on whether pipelines exist, likely causing failures when accessing expected fields like id.

Additional Locations (1)

Fix in Cursor Fix in Web

@bitdeckai bitdeckai force-pushed the bounty-circleci-expand branch from 45c93f8 to 32c0ff5 Compare February 24, 2026 13:17
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

}

func (c *Client) GetWorkflowTestMetrics(projectSlug, workflowName string, filters map[string]string) (map[string]any, error) {
path := fmt.Sprintf("%s/insights/%s/workflows/%s/test-metrics%s", baseURL, projectSlug, workflowName, buildQueryString(filters))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow name not URL encoded in path

High Severity

The workflowName parameter is directly interpolated into the URL path without URL encoding. Workflow names containing spaces, slashes, or special characters will result in malformed URLs and API request failures. The url.PathEscape function wraps path parameters elsewhere in the codebase (see AWS Lambda and Dash0 integrations).

Fix in Cursor Fix in Web

}

pipelineID, _ := firstItem["id"].(string)
workflows, err := c.GetPipelineWorkflows(pipelineID)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation after pipeline ID type assertion

Low Severity

After the type assertion pipelineID, _ := firstItem["id"].(string), the code doesn't check if pipelineID is empty before using it. If the assertion fails or the ID is missing, an empty string gets passed to GetPipelineWorkflows, causing a confusing HTTP error instead of a clear error message. The existing pattern in run_pipeline.go lines 387-390 checks for empty strings after similar type assertions.

Fix in Cursor Fix in Web

"workflow": workflow,
"jobs": jobs,
}
return ctx.ExecutionState.Emit(core.DefaultOutputChannel.Name, "circleci.workflow", []any{output})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different data structures use same event type

Medium Severity

Both GetWorkflow and GetLastWorkflow emit events with type "circleci.workflow", but they output completely different data structures. GetWorkflow emits {workflow, jobs} while GetLastWorkflow emits {pipeline, workflows}. Downstream consumers cannot reliably parse these events because the structure varies by source. In other integrations like GitHub, components that emit the same event type always emit consistent data structures.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CircleCI] Expand Integration

1 participant